import './GraphX6.scss'
import { v4 } from 'uuid'
import { useState, useRef, useEffect } from 'react'
import { useRequest } from 'alova/client'
import { Button, Skeleton, Result, App, Dropdown, Popconfirm } from 'antd'
import { useEventEmitter, useMount } from 'ahooks'


import { Http } from '../../Utils/Api'
import { ICONMapping } from '../../Config/IconMapping'
import { Encrypt, Decrypt } from '../../Utils/IndexedDB'
import { modelStore, drawerStore } from '../../Config/zustand'
import { updateTreeByKey } from '../../Utils'


import { Graph, Shape } from '@antv/x6'
import { register } from '@antv/x6-react-shape'
import { Stencil } from '@antv/x6-plugin-stencil'
import { Transform } from '@antv/x6-plugin-transform'
import { Selection } from '@antv/x6-plugin-selection'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { History } from '@antv/x6-plugin-history'


import { AdminRouter } from '../../Config/default'


const attr = { attrs: { line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } } } }
const circleStyle = { r: 4, magnet: true, stroke: '#5F95FF', strokeWidth: 1, fill: '#fff', style: { visibility: 'hidden' } }

const ports = {
    groups: {
        top: { position: 'top', attrs: { circle: circleStyle } },
        right: { position: 'right', attrs: { circle: circleStyle } },
        bottom: { position: 'bottom', attrs: { circle: circleStyle } },
        left: { position: 'left', attrs: { circle: circleStyle } },
    },
    items: [{ group: 'top' }, { group: 'right' }, { group: 'bottom' }, { group: 'left' }]
}



const GraphX6 = () => {
    const X6Box = useRef()
    const { message, modal, notification } = App.useApp();
    const { send } = useRequest(data => Http(data), { immediate: false })
    const NodeEvent = useEventEmitter()
    const ProcessEvent = useEventEmitter()
    const BackgroundEvent = useEventEmitter()
    const { updateModel } = modelStore()
    const { updateDrawer } = drawerStore()
    const [Loading, setLoading] = useState(false)
    const [ListData, setListData] = useState([])

    const [X6, setGX6] = useState()
    const [Active, setActive] = useState()
    const [NodeActive, setNodeActive] = useState()


    const getListData = () => {
        send({ method: 'get', url: 'dictionary/GetJsonInfoByUuid', params: { uuid: 'ProcessConfig' } }).then(async res => {
            setListData(await Decrypt(res))
            setLoading(true)
        })
    }

    const saveListData = async (data) => {
        const json = X6.toJSON()
        console.log(json)
        data.find(v => v.uuid === Active).x6Data = json
        send({ method: 'post', url: 'dictionary/SaveJsonInfoByUuid', params: { uuid: 'ProcessConfig', content: JSON.stringify(await Encrypt(data)) } }).then(() => {
            notification.success({ message: '保存成功!', description: '流程内容保存成功!' })
        })
    }

    const onAdd = () => {
        updateModel({ type: 'AddFormData', width: 640, title: '新增流程', data: { type: 'AddProcessItem', AddEvnet: ProcessEvent } })
    }

    const onUpLoad = (data) => {
        const arr = [...ListData, { uuid: v4(), ...data, x6Style: AdminRouter.X6BackGround }]
        setListData(arr)
        saveListData(arr)
        ProcessEvent.emit({ type: 'closeForm' })
    }

    const onActive = uuid => {
        setActive(uuid)
        onInitX6(uuid)
    }

    const onInitX6 = (uuid) => {
        if (ListData && X6Box.current) {
            const { x6Data, x6Style } = ListData.find(item => item.uuid === uuid)

            console.log(new Shape.Edge(attr))
            const graph = new Graph({
                container: X6Box.current,
                grid: x6Style.grid,
                background: x6Style.background,
                mousewheel: { enabled: true, modifiers: ['ctrl', 'meta'] },
                connecting: { //链接设置
                    router: 'manhattan',
                    connector: { name: 'rounded', args: { radius: 8 } },
                    anchor: 'center',
                    connectionPoint: 'anchor',
                    allowBlank: false,
                    snap: { radius: 20 },


                    allowLoop: false,
                    allowNode: false,

                    createEdge() { return new Shape.Edge(attr) },
                    validateConnection({ targetMagnet }) { return !!targetMagnet }
                },
            })
            graph.on('edge:mouseenter', ({ cell }) => {
                cell.addTools([
                    { name: 'source-arrowhead', args: { attrs: { fill: '#1677ff' } } },
                    { name: 'target-arrowhead', args: { attrs: { fill: '#f5222d' } } },
                ])
            })
            graph.on('edge:mouseleave', ({ cell }) => cell.removeTools())
            graph
                .use(new Transform({ resizing: true, rotating: true }))
                .use(new Selection({ rubberband: true, showNodeSelectionBox: true }))
                .use(new Stencil())
                .use(new Snapline())
                .use(new Keyboard())
                .use(new Clipboard())
                .use(new History())
            graph.fromJSON(x6Data || {})
            graph.centerContent()
            const showPorts = (ports, show) => { for (let i = 0, len = ports.length; i < len; i += 1) { ports[i].style.visibility = show ? 'visible' : 'hidden' } }
            graph.on('node:mouseenter', () => showPorts(X6Box.current.querySelectorAll('.x6-port-body'), true))
            graph.on('node:mouseleave', () => showPorts(X6Box.current.querySelectorAll('.x6-port-body'), false))
            setGX6(graph)

        } else setTimeout(() => onInitX6(uuid), 500)
    }


    const onAddNode = () => {
        updateDrawer({ type: 'AddFormData', width: 640, title: '编辑节点', data: { type: 'AddProcessNode', AddEvnet: NodeEvent, Initial: AdminRouter.X6Node } })
    }

    const onBackConfig = () => {
        const { x6Style } = ListData.find(item => item.uuid === Active)
        updateDrawer({ type: 'AddFormData', width: 640, title: '新增流程', data: { type: 'AddProcessBack', AddEvnet: BackgroundEvent, Initial: x6Style } })
    }

    const onSetBack = (data) => {
        const { background, grid } = data
        updateTreeByKey(ListData, Active, data, 'uuid', 'x6Style')
        X6.drawBackground(background)
        X6.drawGrid(grid)
        X6.setGridSize(grid.size)
    }

    const onSetNode = (data) => {
        if (NodeActive) {
            const NodeData = X6.getNodes().find(v => v.id === NodeActive)
            NodeData.attr('text', data)
        } else X6.addNode({ shape: 'custom-react-node', width: 100, height: 100, tools: ['button-remove'], ports, attrs: { text: data } })
        NodeEvent.emit({ type: 'closeForm' })
    }

    const onDelete = () => {
        const arr = ListData.filter(item => item.uuid !== Active)
        setListData(arr)
        saveListData(arr)
        setActive()
    }

    const CallBackFunc = (e) => {
        const { type, data } = e
        // console.log(type, data)
        const MapReturn = new Map([
            ['onFormBack', () => onUpLoad(data)]
        ])
        const func = MapReturn.get(type)
        return func && func()
    }

    const CallBackFuncBack = (e) => {
        const { type, data } = e
        const MapReturn = new Map([
            ['onFormBack', () => onSetBack(data)]
        ])
        const func = MapReturn.get(type)
        return func && func()
    }
    const CallBackFuncNode = (e) => {
        const { type, data } = e
        const MapReturn = new Map([
            ['onFormBack', () => onSetNode(data)]
        ])
        const func = MapReturn.get(type)
        return func && func()
    }

    NodeEvent.useSubscription(CallBackFuncNode)
    ProcessEvent.useSubscription(CallBackFunc)
    BackgroundEvent.useSubscription(CallBackFuncBack)
    useMount(getListData)

    const CustomComponent = ({ node }) => {
        const { text, color, fontSize, fontFamily, fontWeight, fontStyle, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor,
            type, radius, background, borderSize, borderStyle, borderColor } = node.attrs.text
        const textStyle = {
            color,
            fontSize,
            fontFamily,
            fontWeight,
            fontStyle,
            filter: `drop-shadow(${shadowOffsetX}px ${shadowOffsetY}px ${shadowBlur}px ${shadowColor})`,
        }
        const backStyle = {
            background,
            borderRadius: radius,
            border: `${borderSize}px ${borderStyle} ${borderColor}`,
        }
        const onModifyStyle = () => {
            setNodeActive(node.id)
            updateDrawer({ type: 'AddFormData', width: 640, title: '编辑节点', data: { type: 'AddProcessNode', AddEvnet: NodeEvent, Initial: node.attrs.text } })
        }


        return (
            <Dropdown trigger={['contextMenu']} menu={{
                items: [
                    { key: 'A01', label: (<Button type='line' onClick={onModifyStyle} >样式配置</Button>) },
                    { key: 'A02', label: (<Button type='line' >功能配置</Button>) },
                ]
            }} >
                <div className={`custom-react-node ${type}`} style={backStyle}>
                    <div style={textStyle}>{text}</div>
                </div>
            </Dropdown>
        )
    }

    register({ shape: 'custom-react-node', component: CustomComponent })

    return (
        <div className='GraphX6'>
            <div className='List'>
                {Loading ?
                    ListData.length !== 0 ?
                        <>
                            <div className='List_item'>
                                {ListData.map(({ uuid, process_icon, process_name, process_color }) =>
                                    <div
                                        key={uuid}
                                        className={Active === uuid ? 'active' : ''}
                                        style={{ background: process_color }}
                                        onClick={() => onActive(uuid)}
                                    >
                                        {ICONMapping[process_icon]}
                                        <div>{process_name}</div>
                                    </div>
                                )}
                            </div>
                            <Button type='primary' onClick={onAdd}>新增流程</Button>
                        </> :
                        <Result status="404" title="无可用流程" extra={<Button type="primary" onClick={onAdd}>新增流程</Button>} /> :
                    <Skeleton active paragraph={{ rows: 24 }} />
                }
            </div>
            <div className='Content'>
                {Active &&
                    <>
                        <div className='Graph' ref={X6Box}></div>
                        <div className='Options'>
                            <Button type='primary' onClick={onAddNode}>新增节点</Button>
                            <Button type='primary' onClick={() => saveListData(ListData)}>保存流程</Button>
                            <Button type='primary' onClick={onBackConfig}>背景配置</Button>
                            <Popconfirm
                                title="删除提醒!"
                                description="是否删除当前流程?"
                                onConfirm={onDelete}
                                okText="删除"
                                cancelText="取消"
                            >
                                <Button type='primary' danger >删除流程</Button>
                            </Popconfirm>
                        </div>
                    </>
                }
            </div>
        </div>
    );
};

export default GraphX6;